﻿#define _CRT_SECURE_NO_WARNINGS

#include<iostream>
#include<vector>
#include<map>
#include<assert.h>
#include<string>
#include<string.h>
#include<algorithm>
#include<list>
#include<functional>
#include<exception>
#include<thread>
#include<memory>
#include<mutex>
#include<atomic>

using namespace std;


//左值和右值

//struct Point
//{
//	int _x;
//	int _y;
//};
//int main()
//{
//	int array1[] = { 1, 2, 3, 4, 5 };
//	int array2[5] = { 0 };
//	Point p = { 1, 2 };
//	return 0;
//}

//struct Point
//{
//	int _x;
//	int _y;
//};
//class Date
//{
//public:
//	Date(int year = 1, int month = 1, int day = 1)
//		:_year(year)
//		, _month(month)
//		, _day(day)
//	{
//		cout << "Date(int year, int month, int day)" << endl;
//	}
//	Date(const Date& d)
//		:_year(d._year)
//		, _month(d._month)
//		, _day(d._day)
//	{
//		cout << "Date(const Date& d)" << endl;
//	}
//private:
//	int _year;
//	int _month;
//	int _day;
//};
//// ⼀切皆可⽤列表初始化，且可以不加=
//int main()
//{
//	// C++98⽀持的
//	int a1[] = { 1, 2, 3, 4, 5 };
//	int a2[5] = { 0 };
//	Point p = { 1, 2 };
//
//	// C++11⽀持的
//	// 内置类型⽀持
//	int x1 = { 2 };
//
//	// ⾃定义类型⽀持
//	// 这⾥本质是⽤{ 2025, 1, 1}构造⼀个Date临时对象
//	// 临时对象再去拷⻉构造d1，编译器优化后合⼆为⼀变成{ 2025, 1, 1}直接构造初始化d1
//		// 运⾏⼀下，我们可以验证上⾯的理论，发现是没调⽤拷⻉构造的
//	Date d1 = { 2025, 1, 1 };
//
//	// 这⾥d2引⽤的是{ 2024, 7, 25 }构造的临时对象
//	const Date& d2 = { 2024, 7, 25 };
//
//	// 需要注意的是C++98⽀持单参数时类型转换，也可以不⽤{}
//	Date d3 = { 2025 }; //C++11
//	Date d4 = 2025;     //C++98
//
//	// 可以省略掉=
//	Point p1{ 1, 2 };
//	int x2{ 2 };
//	Date d6{ 2024, 7, 25 };
//	const Date& d7{ 2024, 7, 25 };
//
//	// 不⽀持，只有{}初始化，才能省略=
//	// Date d8 2025;
//
//	vector<Date> v;
//	v.push_back(d1);
//	v.push_back(Date(2025, 1, 1));
//
//	// ⽐起有名对象和匿名对象传参，这⾥{}更有性价⽐
//	v.push_back({ 2025, 1, 1 });
//	map<string, string> dict;
//	dict.insert({ "xxx","yyy" });
//
//	//构造+拷贝构造+优化
//	/*vector<int>v1 = { 1,2,3,4 };
//	vector<int>v2 = { 1,2,3,4 };
//	const vector<int>& v4 = { 10,20,30,1,1,1,1,1,1 };*/
//
//	vector<int>v1  { 1,2,3,4 };
//	vector<int>v2 { 1,2,3,4 };
//	const vector<int>& v4 { 10,20,30,1,1,1,1,1,1 };
//
//	//构造
//	vector<int> v3({ 10,20,30,1,1,1,1,1,1 });
//
//	initializer_list<int> il1 = { 10,20,30,1,1,1,1,1,1 };
//	int aa1[] = { 10,20,30,1,1,1,1,1,1 };
//
//	//initializer_list +{}pair初始化隐式类型转换
//	map<string, string> dict = { {"xxx","yyy"},{"sort","zzzz"} };
//
//	return 0;
//}


//int main()
//{
//	// 左值：可以取地址
//	// 以下的p、b、c、*p、s、s[0]就是常⻅的左值
//	int* p = new int(0);
//	int b = 1;
//	const int c = b;
//	*p = 10;
//	string s("111111");
//	s[0] = 'x';
//
//	cout << &c << endl;
//	cout << (void*)&s[0] << endl;
//
//	// 右值：不能取地址
//	double x = 1.1, y = 2.2;
//
//	// 以下⼏个10、x + y、fmin(x, y)、string("11111")都是常⻅的右值
//	10;
//	x + y;
//	fmin(x, y);
//	string("11111");
//
//	//cout << &10 << endl;
//	//cout << &(x+y) << endl;
//	//cout << &(fmin(x, y)) << endl;
//	//cout << &string("11111") << endl;
//
//	return 0;
//}


//template <class _Ty>
//remove_reference_t<_Ty>&& move(_Ty&& _Arg)
//{ // forward _Arg as movable
//	return static_cast<remove_reference_t<_Ty>&&>(_Arg);
//}
//int main()
//{
//	// 左值：可以取地址
//	// 以下的p、b、c、*p、s、s[0]就是常⻅的左值
//	int* p = new int(0);
//	int b = 1;
//	const int c = b;
//	*p = 10;
//	string s("111111");
//	s[0] = 'x';
//	double x = 1.1, y = 2.2;
//
//	// 左值引⽤给左值取别名
//	int& r1 = b;
//	int*& r2 = p;
//	int& r3 = *p;
//	string& r4 = s;
//	char& r5 = s[0];
//
//	// 右值引⽤给右值取别名
//	int&& rr1 = 10;
//	double&& rr2 = x + y;
//	double&& rr3 = fmin(x, y);
//	string&& rr4 = string("11111");
//
//	// 左值引⽤不能直接引⽤右值，但是const左值引⽤可以引⽤右值
//	const int& rx1 = 10;
//	const double& rx2 = x + y;
//	const double& rx3 = fmin(x, y);
//	const string& rx4 = string("11111");
//
//	// 右值引⽤不能直接引⽤左值，但是右值引⽤可以引⽤move(左值)
//	int&& rrx1 = move(b);
//	int*&& rrx2 = move(p);
//	int&& rrx3 = move(*p);
//	string&& rrx4 = move(s);
//	string&& rrx5 = (string&&)s;
//
//	// b、r1、rr1都是变量表达式，都是左值
//	cout << &b << endl;
//	cout << &r1 << endl;
//	cout << &rr1 << endl;
//
//	// 这⾥要注意的是，rr1的属性是左值，所以不能再被右值引⽤绑定，除⾮move⼀下
//	int& r6 = rr1;
//
//	// int&& rrx6 = rr1;
//	int&& rrx6 = move(rr1);
//
//	return 0;
//}	


//右值引⽤可⽤于为临时对象延⻓⽣命周期，const 的左值引⽤也能延⻓临时对象⽣存期，但这些对象⽆法被修改。
//int main()
//{
//	std::string s1 = "Test";
//	// std::string&& r1 = s1; // 错误：不能绑定到左值
//	const std::string& r2 = s1 + s1; // OK：到 const 的左值引⽤延⻓⽣存期
//	// r2 += "Test"; // 错误：不能通过到 const 的引⽤修改
//	std::string&& r3 = s1 + s1; // OK：右值引⽤延⻓⽣存期
//	r3 += "Test"; // OK：能通过到⾮ const 的引⽤修改
//	std::cout << r3 << '\n';
//	return 0;
//}


//分别重载左值引⽤、const左值引⽤、右值引⽤作为形参的f函数，那么实参是左值会
//匹配f(左值引⽤)，实参是const左值会匹配f(const 左值引⽤)，实参是右值会匹配f(右值引⽤)。
//void f(int& x)
//{
//	std::cout << "左值引⽤重载 f(" << x << ")\n";
//}
//void f(const int& x)
//{
//	std::cout << "到 const 的左值引⽤重载 f(" << x << ")\n";
//}
//void f(int&& x)
//{
//	std::cout << "右值引⽤重载 f(" << x << ")\n";
//}
//int main()
//{
//	int i = 1;
//	const int ci = 2;
//
//	f(i); // 调⽤ f(int&)
//	f(ci); // 调⽤ f(const int&)
//	f(3); // 调⽤ f(int&&)，如果没有 f(int&&) 重载则会调⽤ f(const int&)
//	f(std::move(i)); // 调⽤ f(int&&)
//
//	// 右值引⽤变量在⽤于表达式时是左值
//	int&& x = 1;
//	f(x); // 调⽤ f(int& x)
//	f(std::move(x)); // 调⽤ f(int&& x)
//
//	return 0;
//}


//class Solution {
//public:
//	// 传值返回需要拷⻉
//	string addStrings(string num1, string num2) {
//		string str;
//		int end1 = num1.size() - 1, end2 = num2.size() - 1;
//		// 进位
//		int next = 0;
//		while (end1 >= 0 || end2 >= 0)
//		{
//			int val1 = end1 >= 0 ? num1[end1--] - '0' : 0;
//			int val2 = end2 >= 0 ? num2[end2--] - '0' : 0;
//			int ret = val1 + val2 + next;
//			next = ret / 10;
//			ret = ret % 10;
//			str += ('0' + ret);
//		}
//
//		if (next == 1)
//			str += '1';
//
//		reverse(str.begin(), str.end());
//
//		return str;
//	}
//};

//class Solution {
//public:
//	// 这⾥的传值返回拷⻉代价就太⼤了
//	vector<vector<int>> generate(int numRows) 
//	{
//		vector<vector<int>> vv(numRows);
//		for (int i = 0; i < numRows; ++i)
//		{
//			vv[i].resize(i + 1, 1);
//		}
//
//		for (int i = 2; i < numRows; ++i)
//		{
//			for (int j = 1; j < i; ++j)
//			{
//				vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
//			}
//		}
//
//		return vv;
//	}
//};

//int main()
//{
//	string ret = Solution().addStrings("11111111", "2222222222222222");
//	cout << ret << endl;
//	return 0;
//}


namespace wzz
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;

		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}

		const_iterator begin() const
		{
			return _str;
		}
		const_iterator end() const
		{
			return _str + _size;
		}

		string(const char* str = "")
			:_size(strlen(str))
			, _capacity(_size)
		{
			cout << "string(char* str)-构造" << endl;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}

		void swap(string& s)
		{
			::swap(_str, s._str);
			::swap(_size, s._size);
			::swap(_capacity, s._capacity);
		}

		string(const string& s)
			:_str(nullptr)
		{
			cout << "string(const string& s) -- 拷贝构造" << endl;
			reserve(s._capacity);
			for (auto ch : s)
			{
				push_back(ch);
			}
		}

		// 移动构造
		string(string&& s)
		{
			cout << "string(string&& s) -- 移动构造" << endl;
			swap(s);
		}

		string& operator=(const string& s)
		{
			cout << "string& operator=(const string& s) -- 拷贝赋值" <<endl;
			if (this != &s)
			{
				_str[0] = '\0';
				_size = 0;
				reserve(s._capacity);
				for (auto ch : s)
				{
					push_back(ch);
				}
			}
			return *this;
		}

		// 移动赋值
		string& operator=(string&& s)
		{
			cout << "string& operator=(string&& s) -- 移动赋值" << endl;
			swap(s);
			return *this;
		}

		~string()
		{
			cout << "~string() -- 析构" << endl;
			delete[] _str;
			_str = nullptr;
		}

		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}

		void reserve(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				if (_str)
				{
					strcpy(tmp, _str);
					delete[] _str;
				}
				_str = tmp;
				_capacity = n;
			}
		}

		void push_back(char ch)
		{
			if (_size >= _capacity)
			{
				size_t newcapacity = _capacity == 0 ? 4 : _capacity *
					2;
				reserve(newcapacity);
			}
			_str[_size] = ch;
			++_size;
			_str[_size] = '\0';
		}

		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}

		const char* c_str() const
		{
			return _str;
		}
		size_t size() const
		{
			return _size;
		}

	private:
		char* _str = nullptr;
		size_t _size = 0;
		size_t _capacity = 0;
	};
}
//int main()
//{
//	wzz::string s1("xxxxx");
//	// 拷⻉构造
//	wzz::string s2 = s1;
//	// 构造+移动构造，优化后直接构造
//	wzz::string s3 = wzz::string("yyyyy");
//	// 移动构造
//	wzz::string s4 = move(s1);
//	cout << "******************************" << endl;
//
//	return 0;
//}


//引⽤折叠
//• C++中不能直接定义引⽤的引⽤如 int&&& r = i; ，这样写会直接报错，通过模板或 typedef中的类型操作可以构成引⽤的引⽤。
//• 通过模板或 typedef 中的类型操作可以构成引⽤的引⽤时，这时C++11给出了⼀个引⽤折叠的规则：
//	右值引⽤的右值引⽤折叠成右值引⽤，所有其他组合均折叠成左值引⽤。

// 由于引⽤折叠限定，f1实例化以后总是⼀个左值引⽤
//template<class T>
//void f1(T& x)
//{}
//// 由于引⽤折叠限定，f2实例化后可以是左值引⽤，也可以是右值引⽤
//template<class T>
//void f2(T&& x)
//{}
//int main()
//{
//	typedef int& lref;
//	typedef int&& rref;
//	int n = 0;
//
//	lref& r1 = n; // r1 的类型是 int&
//	lref&& r2 = n; // r2 的类型是 int&
//	rref& r3 = n; // r3 的类型是 int&
//	rref&& r4 = 1; // r4 的类型是 int&&
//
//	// 没有折叠->实例化为void f1(int& x)
//	f1<int>(n);
//	//f1<int>(0); // 报错
//
//	// 折叠->实例化为void f1(int& x)
//	f1<int&>(n);
//	//f1<int&>(0); // 报错
//
//	// 折叠->实例化为void f1(int& x)
//	f1<int&&>(n);
//	//f1<int&&>(0); // 报错
//
//	// 折叠->实例化为void f1(const int& x)
//	f1<const int&>(n);
//	f1<const int&>(0);
//
//	// 折叠->实例化为void f1(const int& x)
//	f1<const int&&>(n);
//	f1<const int&&>(0);
//
//	// 没有折叠->实例化为void f2(int&& x)
//	//f2<int>(n); // 报错
//	f2<int>(0);
//
//	// 折叠->实例化为void f2(int& x)
//	f2<int&>(n);
//	//f2<int&>(0); // 报错
//
//	// 折叠->实例化为void f2(int&& x)
//	//f2<int&&>(n); // 报错
//	f2<int&&>(0);
//
//	return 0;
//}

//template<class T>
//void Function(T&& t)
//{
//	int a = 0;
//	T x = a;
//	//x++;
//	cout << &a << endl;
//	cout << &x << endl << endl;
//}
//int main()
//{
//	// 10是右值，推导出T为int，模板实例化为void Function(int&& t)
//	Function(10); // 右值
//
//	int a;
//	// a是左值，推导出T为int&，引⽤折叠，模板实例化为void Function(int& t)
//	Function(a); // 左值
//
//	// std::move(a)是右值，推导出T为int，模板实例化为void Function(int&& t)
//	Function(std::move(a)); // 右值
//
//	const int b = 8;
//	// b是左值，推导出T为const int&，引⽤折叠，模板实例化为void Function(const int&t)
//	// 所以Function内部会编译报错，x不能++
//
//	Function(b); // const 左值
//	// std::move(b)右值，推导出T为const int，模板实例化为void Function(const int&&t)
//	
//	// 所以Function内部会编译报错，x不能++
//	Function(std::move(b)); // const 右值
//
//	return 0;
//}

//template <class _Ty>
//_Ty&& forward(remove_reference_t<_Ty>& _Arg) noexcept
//{ 
//	// forward an lvalue as either an lvalue or an rvalue
//	return static_cast<_Ty&&>(_Arg);
//}

//void Fun(int& x) { cout << "左值引用" << endl; }
//void Fun(const int& x) { cout << "const 左值引用" << endl; }
//
//void Fun(int&& x) { cout << "右值引用" << endl; }
//void Fun(const int&& x) { cout << "const 右值引用" << endl; }
//
//template<class T>
//void Function(T&& t)
//{
//	Fun(t);
//	//Fun(forward<T>(t));
//}
//int main()
//{
//	// 10是右值，推导出T为int，模板实例化为void Function(int&& t)
//	Function(10); // 右值
//
//	int a;
//	// a是左值，推导出T为int&，引⽤折叠，模板实例化为void Function(int& t)
//	Function(a); // 左值
//
//	// std::move(a)是右值，推导出T为int，模板实例化为void Function(int&& t)
//	Function(std::move(a)); // 右值
//
//	const int b = 8;
//	// b是左值，推导出T为const int&，引⽤折叠，模板实例化为void Function(const int&t)
//
//	Function(b); // const 左值
//	// std::move(b)右值，推导出T为const int，模板实例化为void Function(const int&&t)
//	Function(std::move(b)); // const 右值\
//
//	return 0;
//}


//int main()
//{
//	string s1("1111111");
//
//	list<string> lt;
//	lt.push_back(s1);
//
//	string s2("2222222222");
//	lt.push_back(move(s2));
//
//	lt.push_back(s2);
//
//
//	return 0;
//}

//
// C++11⽀持可变参数模板，也就是说⽀持可变数量参数的函数模板和类模板，可变数⽬的参数被称为参数包，
// 存在两种参数包：模板参数包，表⽰零或多个模板参数；函数参数包：表⽰零或多个函数参数
// ⽤省略号来指出⼀个模板参数或函数参数的表⽰⼀个包，在模板参数列表中，class...或
// typename...指出接下来的参数表⽰零或多个类型列表；在函数参数列表中，类型名后⾯跟...指出
// 接下来表⽰零或多个形参对象列表；函数参数包可以⽤左值引⽤或右值引⽤表⽰，跟前⾯普通模板⼀样，
// 每个参数实例化时遵循引⽤折叠规则。
//• 可变参数模板的原理跟模板类似，本质还是去实例化对应类型和个数的多个函数。
//• 这⾥我们可以使⽤sizeof...运算符去计算参数包中参数的个数
// 
// 0~N个参数
//template <class ...Args>
//void Print(Args&&... args)
//{
//	cout << sizeof...(args) << endl;
//}
//int main()
//{
//	double x = 2.2;
//	Print(); // 包⾥有0个参数
//	Print(1); // 包⾥有1个参数
//	Print(1, string("xxxxx")); // 包⾥有2个参数
//	Print(1.1, string("xxxxx"), x); // 包⾥有3个参数
//
//	return 0;
//}

//// 原理1：编译本质这⾥会结合引⽤折叠规则实例化出以下四个函数
//void Print();
//void Print(int&& arg1);
//void Print(int&& arg1, string&& arg2);
//void Print(double&& arg1, string&& arg2, double& arg3);
//
//// 原理2：更本质去看没有可变参数模板，我们实现出这样的多个函数模板才能⽀持这⾥的功能，
//// 有了可变参数模板，我们进⼀步被解放，他是类型泛化基础上叠加数量变化，让我们泛型编程更灵活。
//void Print();
//
//template <class T1>
//void Print(T1&& arg1);
//
//template <class T1, class T2>
//void Print(T1&& arg1, T2&& arg2);
//
//template <class T1, class T2, class T3>
//void Print(T1&& arg1, T2&& arg2, T3&& arg3);

//• 对于⼀个参数包，我们除了能计算他的参数个数，我们能做的唯⼀的事情就是扩展它，当扩展⼀个包时，
//  我们还要提供⽤于每个扩展元素的模式，扩展⼀个包就是将它分解为构成的元素，对每个元素应⽤模式，
//  获得扩展后的列表。我们通过在模式的右边放⼀个省略号(...)来触发扩展操作。底层的实现细节如图1所⽰。
//• C++还⽀持更复杂的包扩展，直接将参数包依次展开依次作为实参给⼀个函数去处理

// 可变模板参数
// 参数类型可变
// 参数个数可变
// 打印参数包内容
//template <class ...Args>
//void Print(Args... args)
//{
// // 可变参数模板编译时解析
// // 下⾯是运⾏获取和解析，所以不⽀持这样⽤
// cout << sizeof...(args) << endl;
// for (size_t i = 0; i < sizeof...(args); i++)
// {
// cout << args[i] << " ";
// }
// cout << endl;
//}
//void ShowList()
//{
//	// 编译器时递归的终⽌条件，参数包是0个时，直接匹配这个函数
//	cout << endl;
//}
//template <class T, class ...Args>
//void ShowList(T x, Args... args)
//{
//	cout << x << " ";
//	// args是N个参数的参数包
//	// 调⽤ShowList，参数包的第⼀个传给x，剩下N-1传给第⼆个参数包
//	ShowList(args...);
//}
//// 编译时递归推导解析参数
//template <class ...Args>
//void Print(Args... args)
//{
//	ShowList(args...);
//}
//int main()
//{
//	Print();
//	Print(1);
//	Print(1, string("xxxxx"));
//	Print(1, string("xxxxx"), 2.2);
//	return 0;
//}
////template <class T, class ...Args>
////void ShowList(T x, Args... args)
////{
//// cout << x << " ";
//// Print(args...);
////}
//// Print(1, string("xxxxx"), 2.2);调⽤时// 本质编译器将可变参数模板通过模式的包扩展，编译器推导的以下三个重载函数函数
// //void ShowList(double x)
// //{
// // cout << x << " ";
// // ShowList();
// //}
// //
// //void ShowList(string x, double z)
// //{
// // cout << x << " ";
// // ShowList(z);
// //}
// //
// //void ShowList(int x, string y, double z)
// //{
// // cout << x << " ";
// // ShowList(y, z);
// //}
//
// //void Print(int x, string y, double z)
// //{
// // ShowList(x, y, z);
// //}

// template < class T>
// const T& GetArg(const T& x)
// {
//	 cout << x << " ";
//	 return x;
// }
//
// template < class ...Args>
// void Arguments(Args... args)
// {}
//
//template < class ...Args>
//void Print(Args... args)
//{
//	// 注意GetArg必须返回或者到的对象，这样才能组成参数包给Arguments
//	Arguments(GetArg(args)...);
//}
//
// // 本质可以理解为编译器编译时，包的扩展模式
// // 将上⾯的函数模板扩展实例化为下⾯的函数
// // 是不是很抽象，C++11以后，只能说委员会的⼤佬设计语法思维跳跃得太厉害
////void Print(int x, string y, double z)
////{
//// Arguments(GetArg(x), GetArg(y), GetArg(z));
////}
//int main()
//{
//	Print(1, string("xxxxx"), 2.2);
//	return 0;
//}


//• template <class... Args> void emplace_back (Args&&... args);
//• template <class... Args> iterator emplace(const_iterator position,	Args&&... args);
//• C++11以后STL容器新增了empalce系列的接⼝，empalce系列的接⼝均为模板可变参数，功能上
//  兼容push和insert系列，但是empalce还⽀持新玩法，假设容器为container<T>，empalce还⽀持
//  直接插⼊构造T对象的参数，这样有些场景会更⾼效⼀些，可以直接在容器空间上构造T对象。
//• emplace_back总体⽽⾔是更⾼效，推荐以后使⽤emplace系列替代insert和push系列
//• 第⼆个程序中我们模拟实现了list的emplace和emplace_back接⼝，这⾥把参数包不段往下传递，
//  最终在结点的构造中直接去匹配容器存储的数据类型T的构造，所以达到了前⾯说的empalce⽀持
//  直接插⼊构造T对象的参数，这样有些场景会更⾼效⼀些，可以直接在容器空间上构造T对象。
//• 传递参数包过程中，如果是 Args&&... args 的参数包，要⽤完美转发参数包，⽅式如下
//  std::forward<Args>(args)... ，否则编译时包扩展后右值引⽤变量表达式就变成了左值。
// emplace_back总体⽽⾔是更⾼效，推荐以后使⽤emplace系列替代insert和push系列
//int main()
//{
//	list<string> lt;
//	// 传左值，跟push_back⼀样，⾛拷⻉构造
//	string s1("111111111111");
//	lt.emplace_back(s1);
//	cout << "*********************************" << endl;
//
//	// 右值，跟push_back⼀样，⾛移动构造
//	lt.emplace_back(move(s1));
//	cout << "*********************************" << endl;
//
//	// 直接把构造string参数包往下传，直接⽤string参数包构造string
//	// 这⾥达到的效果是push_back做不到的
//	lt.emplace_back("111111111111");
//	cout << "*********************************" << endl;
//
//	list<pair<string, int>> lt1;
//	// 跟push_back⼀样
//	// 构造pair + 拷⻉/移动构造pair到list的节点中data上
//	pair<string, int> kv("苹果", 1);
//	lt1.emplace_back(kv);
//	cout << "*********************************" << endl;
//
//	// 跟push_back⼀样
//	lt1.emplace_back(move(kv));
//	cout << "*********************************" << endl;
//
//	////////////////////////////////////////////////////////////////////
//	// 直接把构造pair参数包往下传，直接⽤pair参数包构造pair
//	// 这⾥达到的效果是push_back做不到的
//	lt1.emplace_back("苹果", 1);
//	cout << "*********************************" << endl;
//
//	return 0;
//}


//#include"List.h"
//// emplace_back总体⽽⾔是更⾼效，推荐以后使⽤emplace系列替代insert和push系列
//int main()
//{
//	wzz::list<wzz::string> lt;
//	// 传左值，跟push_back⼀样，⾛拷⻉构造
//	wzz::string s1("111111111111");
//	lt.emplace_back(s1);
//	cout << "*********************************" << endl;
//	// 右值，跟push_back⼀样，⾛移动构造
//	lt.emplace_back(move(s1));
//	cout << "*********************************" << endl;
//	// 直接把构造string参数包往下传，直接⽤string参数包构造string
//	// 这⾥达到的效果是push_back做不到的
//	lt.emplace_back("111111111111");
//	cout << "*********************************" << endl;
//	wzz::list<pair<wzz::string, int>> lt1;
//	// 跟push_back⼀样
//	// 构造pair + 拷⻉/移动构造pair到list的节点中data上
//	pair<wzz::string, int> kv("苹果", 1);
//	lt1.emplace_back(kv);
//	cout << "*********************************" << endl;
//	// 跟push_back⼀样
//	lt1.emplace_back(move(kv));
//	cout << "*********************************" << endl;
//	////////////////////////////////////////////////////////////////////
//	// 直接把构造pair参数包往下传，直接⽤pair参数包构造pair
//
//		// 这⾥达到的效果是push_back做不到的
//	lt1.emplace_back("苹果", 1);
//	cout << "*********************************" << endl;
//	return 0;
//}


//lambda
//• lambda 表达式本质是⼀个匿名函数对象，跟普通函数不同的是他可以定义在函数内部。
//  lambda 表达式语法使⽤层⽽⾔没有类型，所以我们⼀般是⽤auto或者模板参数定义的对象去接收 lambda 对象。
//• lambda表达式的格式：[capture - list](parameters)-> return type{function boby }
//•[capture - list] : 捕捉列表，该列表总是出现在 lambda 函数的开始位置，编译器根据[]来判断接下来的代码是否为 lambda 函数，
//  捕捉列表能够捕捉上下⽂中的变量供 lambda 函数使⽤，捕捉列表可以传值和传引⽤捕捉，
//  具体细节7.2中我们再细讲。捕捉列表为空也不能省略。
//•(parameters) ：参数列表，与普通函数的参数列表功能类似，如果不需要参数传递，则可以连同()⼀起省略
//• ->return type ：返回值类型，⽤追踪返回类型形式声明函数的返回值类型，没有返回值时此部分可省略。
//  ⼀般返回值类型明确情况下，也可省略，由编译器对返回类型进⾏推导。
//•{ function boby } ：函数体，函数体内的实现跟普通函数完全类似，在该函数体内，除了可以使⽤其参数外，
//  还可以使⽤所有捕获到的变量，函数体为空也不能省略。
//int main()
//{
//	// ⼀个简单的lambda表达式
//	auto add1 = [](int x, int y)->int {return x + y; };
//	cout << add1(1, 2) << endl;
//
//	// 1、捕捉为空也不能省略
//	// 2、参数为空可以省略
//	// 3、返回值可以省略，可以通过返回对象⾃动推导
//	// 4、函数题不能省略
//	auto func1 = []
//		{
//			cout << "hello bit" << endl;
//			return 0;
//		};
//
//	func1();
//
//	int a = 0, b = 1;
//	auto swap1 = [](int& x, int& y)
//		{
//			int tmp = x;
//			x = y;
//			y = tmp;
//		};
//	swap1(a, b);
//
//	cout << a << ":" << b << endl;
//
//	return 0;
//}

//struct Goods
//{
//	string _name; // 名字
//	double _price; // 价格
//	int _evaluate; // 评价
//	// ...
//	Goods(const char* str, double price, int evaluate)
//		:_name(str)
//		, _price(price)
//		, _evaluate(evaluate)
//	{}
//};
//
//struct ComparePriceLess
//{
//	bool operator()(const Goods& gl, const Goods& gr)
//	{
//		return gl._price < gr._price;
//	}
//};
//
//struct ComparePriceGreater
//{
//	bool operator()(const Goods& gl, const Goods& gr)
//	{
//		return gl._price > gr._price;
//	}
//};
//
//int main()
//{
//	vector<Goods> v = { { "苹果", 2.1, 5 }, { "⾹蕉", 3, 4 }, { "橙⼦", 2.2, 3
//	}, { "菠萝", 1.5, 4 } };
//
//	// 类似这样的场景，我们实现仿函数对象或者函数指针⽀持商品中
//	// 不同项的⽐较，相对还是⽐较⿇烦的，那么这⾥lambda就很好⽤了
//	sort(v.begin(), v.end(), ComparePriceLess());
//	sort(v.begin(), v.end(), ComparePriceGreater());
//
//	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
//		return g1._price < g2._price;
//		});
//
//	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
//		return g1._price > g2._price;
//		});
//
//	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
//		return g1._evaluate < g2._evaluate;
//		});
//
//	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
//		return g1._evaluate > g2._evaluate;
//		});
//
//	return 0;
//}


//捕捉列表
//• lambda 表达式中默认只能⽤ lambda 函数体和参数中的变量，如果想⽤外层作⽤域中的变量就需要进⾏捕捉
//• 第⼀种捕捉⽅式是在捕捉列表中显⽰的传值捕捉和传引⽤捕捉，捕捉的多个变量⽤逗号分割。[x，y， & z] 表⽰x和y值捕捉，z引⽤捕捉。
//• 第⼆种捕捉⽅式是在捕捉列表中隐式捕捉，我们在捕捉列表写⼀个 = 表⽰隐式值捕捉，在捕捉列表写⼀个 & 表⽰隐式引⽤捕捉，
//  这样我们 lambda 表达式中⽤了那些变量，编译器就会⾃动捕捉那些变量。
//• 第三种捕捉⽅式是在捕捉列表中混合使⽤隐式捕捉和显⽰捕捉。[=, &x]表⽰其他变量隐式值捕捉，
//  x引⽤捕捉；[&, x, y]表⽰其他变量引⽤捕捉，x和y值捕捉。当使⽤混合捕捉时，第⼀个元素必须是
//  & 或 = ，并且 & 混合捕捉时，后⾯的捕捉变量必须是值捕捉，同理 = 混合捕捉时，后⾯的捕捉变量必须是引⽤捕捉。
//• lambda 表达式如果在函数局部域中，他可以捕捉 lambda 位置之前定义的变量，不能捕捉静态局部变量和全局变量，
//  静态局部变量和全局变量也不需要捕捉， lambda 表达式中可以直接使⽤。这也意味着 lambda 表达式如果定义在全局位置，捕捉列表必须为空。
//• 默认情况下， lambda 捕捉列表是被const修饰的，也就是说传值捕捉的过来的对象不能修改，
//  mutable加在参数列表的后⾯可以取消其常量性，也就说使⽤该修饰符后，传值捕捉的对象就可以修改了，
//  但是修改还是形参对象，不会影响实参。使⽤该修饰符后，参数列表不可省略(即使参数为空)。

//int x = 0;
//// 捕捉列表必须为空，因为全局变量不⽤捕捉就可以⽤，没有可被捕捉的变量
//auto func1 = []()
//	{
//		x++;
//	};
//
//int main()
//{
//	// 只能⽤当前lambda局部域和捕捉的对象和全局对象
//	int a = 0, b = 1, c = 2, d = 3;
//	auto func1 = [a, &b]
//		{
//			// 值捕捉的变量不能修改，引⽤捕捉的变量可以修改
//			//a++;
//			b++;
//			int ret = a + b;
//			return ret;
//		};
//	cout << func1() << endl;
//
//	// 隐式值捕捉
//	// ⽤了哪些变量就捕捉哪些变量
//	auto func2 = [=]
//		{
//			int ret = a + b + c;
//			return ret;
//		};
//	cout << func2() << endl;
//
//	// 隐式引⽤捕捉
//	// ⽤了哪些变量就捕捉哪些变量
//	auto func3 = [&]
//		{
//			a++;
//			c++;
//			d++;
//		};
//	func3();
//	cout << a << " " << b << " " << c << " " << d << endl;
//
//	// 混合捕捉1
//	auto func4 = [&, a, b]
//		{
//			//a++;
//			//b++;
//			c++;
//			d++;
//			return a + b + c + d;
//		};
//	func4();
//	cout << a << " " << b << " " << c << " " << d << endl;
//
//	// 混合捕捉1
//	auto func5 = [=, &a, &b]
//		{
//			a++;
//			b++;
//			/*c++;
//			d++;*/
//			return a + b + c + d;
//		};
//	func5();
//	cout << a << " " << b << " " << c << " " << d << endl;
//
//	// 局部的静态和全局变量不能捕捉，也不需要捕捉
//	static int m = 0;
//	auto func6 = []
//		{
//			int ret = x + m;
//			return ret;
//		};
//
//	// 传值捕捉本质是⼀种拷⻉,并且被const修饰了
//	// mutable相当于去掉const属性，可以修改了
//	// 但是修改了不会影响外⾯被捕捉的值，因为是⼀种拷⻉
//	auto func7 = [=]()mutable
//		{
//			a++;
//			b++;
//			c++;
//			d++;
//
//			return a + b + c + d;
//		};
//	cout << func7() << endl;
//	cout << a << " " << b << " " << c << " " << d << endl;
//
//	return 0;
//}

//lambda的原理
//• lambda 的原理和范围for很像，编译后从汇编指令层的⻆度看，压根就没有 lambda 和范围for这样的东西。范围for底层是迭代器，
//  ⽽lambda底层是仿函数对象，也就说我们写了⼀个lambda 以后，编译器会⽣成⼀个对应的仿函数的类。
//• 仿函数的类名是编译按⼀定规则⽣成的，保证不同的 lambda ⽣成的类名不同，lambda参数 / 返回类型 / 
//  函数体就是仿函数operator()的参数 / 返回类型 / 函数体， lambda 的捕捉列表本质是⽣成的仿函数类的成员变量，
// 也就是说捕捉列表的变量都是 lambda 类构造函数的实参，当然隐式捕捉，编译器要看使⽤哪些就传那些对象。

//class Rate
//{
//public:
//	Rate(double rate)
//		: _rate(rate)
//	{}
//	double operator()(double money, int year)
//	{
//		return money * _rate * year;
//	}
//private:
//	double _rate;
//};
//int main()
//{
//	double rate = 0.49;
//
//	// lambda
//	auto r2 = [rate](double money, int year) {
//		return money * rate * year;
//		};
//
//	// 函数对象
//	Rate r1(rate);
//	r1(10000, 2);
//	r2(10000, 2);
//	auto func1 = [] {
//		cout << "hello world" << endl;
//		};
//	func1();
//
//	return 0;
//}


//默认的移动构造和移动赋值
//• 原来C++类中，有6个默认成员函数：构造函数 / 析构函数 / 拷⻉构造函数 / 拷⻉赋值重载 / 取地址重载 / const 取地址重载，
//最后重要的是前4个，后两个⽤处不⼤，默认成员函数就是我们不写编译器会⽣成⼀个默认的。
//C++11 新增了两个默认成员函数，移动构造函数和移动赋值运算符重载。
//• 如果你没有⾃⼰实现移动构造函数，且没有实现析构函数 、拷⻉构造、拷⻉赋值重载中的任意⼀个。
//那么编译器会⾃动⽣成⼀个默认移动构造。默认⽣成的移动构造函数，对于内置类型成员会执
//⾏逐成员按字节拷⻉，⾃定义类型成员，则需要看这个成员是否实现移动构造，如果实现了就调⽤移动构造，没有实现就调⽤拷⻉构造。
//• 如果你没有⾃⼰实现移动赋值重载函数，且没有实现析构函数 、拷⻉构造、拷⻉赋值重载中的任意⼀个，
//那么编译器会⾃动⽣成⼀个默认移动赋值。默认⽣成的移动构造函数，对于内置类型成员会执⾏逐成员按字节拷⻉，
//⾃定义类型成员，则需要看这个成员是否实现移动赋值，如果实现了就调⽤移动赋值，没有实现就调⽤拷⻉赋值。(默认移动赋值跟上⾯移动构造完全类似)
//• 如果你提供了移动构造或者移动赋值，编译器不会⾃动提供拷⻉构造和拷⻉赋值
// 
//class Person
//{
//public:
//	Person(const char* name = "", int age = 0)
//		:_name(name)
//		, _age(age)
//	{}
//
//	/*Person(const Person& p)
//	:_name(p._name)
//	,_age(p._age)
//	{}*/
//
//	/*Person& operator=(const Person& p)
//	{
//		if (this != &p)
//		{
//			_name = p._name;
//			_age = p._age;
//		}
//		return *this;
//	}*/
//
////~Person()
////{}
//private:
//	wzz::string _name;
//	int _age;
//};
//int main()
//{
//	Person s1;
//	Person s2 = s1;
//	Person s3 = std::move(s1);
//	Person s4;
//	s4 = std::move(s2);
//	return 0;
//}


//C++11可以让你更好的控制要使⽤的默认函数。假设你要使⽤某个默认的函数，但是因为⼀些原因这个函数没有默认⽣成。
//⽐如：我们提供了拷⻉构造，就不会⽣成移动构造了，那么我们可以使⽤default关键字显⽰指定移动构造⽣成。
//• 如果能想要限制某些默认函数的⽣成，在C++98中，是该函数设置成private，并且只声明补丁已，这样只要其他⼈想要调⽤就会报错。
//在C++11中更简单，只需在该函数声明加上 = delete即可，该语法指⽰编译器不⽣成对应函数的默认版本，称 = delete修饰的函数为删除函数
//class Person
//{
//public:
//	Person(const char* name = "", int age = 0)
//		:_name(name)
//		, _age(age)
//	{}
//	Person(const Person& p)
//		:_name(p._name)
//		, _age(p._age)
//	{}
//
//	Person(Person&& p) = default;
//
//	//Person(const Person& p) = delete;
//private:
//	wzz::string _name;
//	int _age;
//};
//int main()
//{
//	Person s1;
//	Person s2 = s1;
//	Person s3 = std::move(s1);
//	return 0;
//}


//int f(int a, int b)
//{
//	return a + b;
//}
//struct Functor
//{
//public:
//	int operator() (int a, int b)
//	{
//		return a + b;
//	}
//};
//class Plus
//{
//public:
//	Plus(int n = 10)
//		:_n(n)
//	{}
//	static int plusi(int a, int b)
//	{
//		return a + b;
//	}
//	double plusd(double a, double b)
//	{
//		return (a + b) * _n;
//	}
//private:
//	int _n;
//};
//int main()
//{
//	// 包装各种可调⽤对象
//	function<int(int, int)> f1 = f;
//	function<int(int, int)> f2 = Functor();
//	function<int(int, int)> f3 = [](int a, int b) {return a + b; };
//	cout << f1(1, 1) << endl;
//	cout << f2(1, 1) << endl;
//	cout << f3(1, 1) << endl;
//
//	// 包装静态成员函数
//	// 成员函数要指定类域并且前⾯加&才能获取地址
//	function<int(int, int)> f4 = &Plus::plusi;
//	cout << f4(1, 1) << endl;
//
//	// 包装普通成员函数
//	// 普通成员函数还有⼀个隐含的this指针参数，所以绑定时传对象或者对象的指针过去都可以
//	function<double(Plus*, double, double)> f5 = &Plus::plusd;
//	Plus pd;
//	cout << f5(&pd, 1.1, 1.1) << endl;
//
//	function<double(Plus, double, double)> f6 = &Plus::plusd;
//	cout << f6(pd, 1.1, 1.1) << endl;
//	cout << f6(pd, 1.1, 1.1) << endl;
//
//	function<double(Plus&&, double, double)> f7 = &Plus::plusd;
//	cout << f7(move(pd), 1.1, 1.1) << endl;
//	cout << f7(Plus(), 1.1, 1.1) << endl;
//
//	return 0;
//}


//using placeholders::_1;
//using placeholders::_2;
//using placeholders::_3;
//
//int Sub(int a, int b)
//{
//	return (a - b) * 10;
//}
//
//int SubX(int a, int b, int c)
//{
//	return (a - b - c) * 10;
//}
//
//class Plus
//{
//public:
//	static int plusi(int a, int b)
//	{
//		return a + b;
//	}
//	double plusd(double a, double b)
//	{
//		return a + b;
//	}
//};
//int main()
//{
//	auto sub1 = bind(Sub, _1, _2);
//	cout << sub1(10, 5) << endl;
//	// bind 本质返回的⼀个仿函数对象
//	// 调整参数顺序（不常⽤）
//	// _1代表第⼀个实参
//	// _2代表第⼆个实参
//	// ...
//	auto sub2 = bind(Sub, _2, _1);
//	cout << sub2(10, 5) << endl;
//
//	// 调整参数个数 （常⽤）
//	auto sub3 = bind(Sub, 100, _1);
//	cout << sub3(5) << endl;
//	auto sub4 = bind(Sub, _1, 100);
//	cout << sub4(5) << endl;
//
//	// 分别绑死第123个参数
//	auto sub5 = bind(SubX, 100, _1, _2);
//	cout << sub5(5, 1) << endl;
//	auto sub6 = bind(SubX, _1, 100, _2);
//	cout << sub6(5, 1) << endl;
//	auto sub7 = bind(SubX, _1, _2, 100);
//	cout << sub7(5, 1) << endl;
//
//	// 成员函数对象进⾏绑死，就不需要每次都传递了
//	function<double(Plus&&, double, double)> f6 = &Plus::plusd;
//	Plus pd;
//	cout << f6(move(pd), 1.1, 1.1) << endl;
//	cout << f6(Plus(), 1.1, 1.1) << endl;
//
//	// bind⼀般⽤于，绑死⼀些固定参数
//	function<double(double, double)> f7 = bind(&Plus::plusd, Plus(), _1, _2);
//	cout << f7(1.1, 1.1) << endl;
//
//	// 计算复利的lambda
//	auto func1 = [](double rate, double money, int year)->double {
//		double ret = money;
//		for (int i = 0; i < year; i++)
//		{
//			ret += ret * rate;
//		}
//		return ret - money;
//		};
//
//	// 绑死⼀些参数，实现出⽀持不同年华利率，不同⾦额和不同年份计算出复利的结算利息
//	function<double(double)> func3_1_5 = bind(func1, 0.015, _1, 3);
//	function<double(double)> func5_1_5 = bind(func1, 0.015, _1, 5);
//	function<double(double)> func10_2_5 = bind(func1, 0.025, _1, 10);
//	function<double(double)> func20_3_5 = bind(func1, 0.035, _1, 20);
//
//	cout << func3_1_5(1000000) << endl;
//	cout << func5_1_5(1000000) << endl;
//	cout << func10_2_5(1000000) << endl;
//	cout << func20_3_5(1000000) << endl;
//
//	return 0;
//}


//异常
//double Divide(int a, int b)
//{
//	try
//	{
//		// 当b == 0时抛出异常
//		if (b == 0)
//		{
//			string s("Divide by zero condition!");
//			throw s;
//		}
//		else
//		{
//			return ((double)a / (double)b);
//		}
//	}
//	catch (int errid)
//	{
//		cout << errid << endl;
//	}
//
//	return 0;
//}
//void Func()
//{
//	int len, time;
//	cin >> len >> time;
//	try
//	{
//		cout << Divide(len, time) << endl;
//	}
//	catch (const char* errmsg)
//	{
//		cout << errmsg << endl;
//	}
//	cout << __FUNCTION__ << ":" << __LINE__ << "⾏执⾏" << endl;
//}
//int main()
//{
//	while (1)
//	{
//		try
//		{
//			Func();
//		}
//		catch (const string& errmsg)
//		{
//			cout << errmsg << endl;
//		}
//	}
//	return 0;
//}


// ⼀般⼤型项⽬程序才会使⽤异常，下⾯我们模拟设计⼀个服务的⼏个模块
// 每个模块的继承都是Exception的派⽣类，每个模块可以添加⾃⼰的数据
// 最后捕获时，我们捕获基类就可以
//class Exception
//{
//public:
//	Exception(const string& errmsg, int id)
//		:_errmsg(errmsg)
//		, _id(id)
//	{}
//	virtual string what() const
//	{
//		return _errmsg;
//	}
//	int getid() const
//	{
//		return _id;
//	}
//protected:
//	string _errmsg;
//	int _id;
//};
//
//class SqlException : public Exception
//{
//public:
//	SqlException(const string& errmsg, int id, const string& sql)
//		:Exception(errmsg, id)
//		, _sql(sql)
//	{}
//	virtual string what() const
//	{
//		string str = "SqlException:";
//		str += _errmsg;
//		str += "->";
//		str += _sql;
//		return str;
//	}
//private:
//	const string _sql;
//};
//
//class CacheException : public Exception
//{
//public:
//	CacheException(const string& errmsg, int id)
//		:Exception(errmsg, id)
//	{}
//	virtual string what() const
//	{
//		string str = "CacheException:";
//		str += _errmsg;
//		return str;
//	}
//};
//
//class HttpException : public Exception
//{
//public:
//	HttpException(const string& errmsg, int id, const string& type)
//		:Exception(errmsg, id)
//		, _type(type)
//	{}
//	virtual string what() const
//	{
//		string str = "HttpException:";
//		str += _type;
//		str += ":";
//		str += _errmsg;
//		return str;
//	}
//private:
//	const string _type;
//};
//
//void SQLMgr()
//{
//	if (rand() % 7 == 0)
//	{
//		throw SqlException("权限不足", 100, "select * from name = '张三'");
//	}
//	else
//	{
//		cout << "SQLMgr 调用成功" << endl;
//	}
//}
//
//void CacheMgr()
//{
//	if (rand() % 5 == 0)
//	{
//		throw CacheException("权限不足", 100);
//	}
//	else if (rand() % 6 == 0)
//	{
//		throw CacheException("数据不存在", 101);
//	}
//	else
//	{
//		cout << "CacheMgr 调用成功" << endl;
//	}
//	SQLMgr();
//}
//
//void HttpServer()
//{
//	if (rand() % 3 == 0)
//	{
//		throw HttpException("请求资源不存在", 100, "get");
//	}
//	else if (rand() % 4 == 0)
//	{
//		throw HttpException("权限不足", 101, "post");
//	}
//	else
//	{
//		cout << "HttpServer调用成功" << endl;
//	}
//	CacheMgr();
//}
//
//int main()
//{
//	srand(time(0));
//	while (1)
//	{
//		this_thread::sleep_for(chrono::seconds(1));
//		try
//		{
//			 HttpServer();
//			
//		}
//		 catch (const Exception& e) // 这⾥捕获基类，基类对象和派⽣类对象都可以被捕获
//		 {
//			 cout << e.what() << endl;
//		 }
//		 catch (...)
//			 {
//			 cout << "Unkown Exception" << endl;
//			 }
//		
//	}
//	
//		 return 0;
//	
//}


// 下⾯程序模拟展⽰了聊天时发送消息，发送失败补货异常，但是可能在电梯地下室等场景⼿机信号不好，则需要多次尝试，如果多次尝试都发
// 送不出去，则就需要捕获异常再重新抛出，其次如果不是⽹络差导致的错误，捕获后也要重新抛出。
// void _SendMsg(const string & s)
// {
//	 if (rand() % 2 == 0)
//		 {
//		 throw HttpException("⽹络不稳定，发送失败", 102, "put");
//		 }
//	 else if (rand() % 7 == 0)
//		 {
//		 throw HttpException("你已经不是对象的好友，发送失败", 103, "put");
//		 }
//	 else
//	 {
//		 cout << "发送成功" << endl;
//		 }
//	 }
//
// void SendMsg(const string & s)
//{
//		// 发送消息失败，则再重试3次
//		for (size_t i = 0; i < 4; i++)
//		{
//			try
//			{
//				_SeedMsg(s);
//				break;
//			}
//			catch (const Exception& e)
//			{
//				// 捕获异常，if中是102号错误，⽹络不稳定，则重新发送
//				// 捕获异常，else中不是102号错误，则将异常重新抛出
//				if (e.getid() == 102)
//				{
//					// 重试三次以后否失败了，则说明⽹络太差了，重新抛出异常
//					if (i == 3)
//						throw;
//					cout << "开始第" << i + 1 << "重试" << endl;
//				}
//				else
//				{
//					throw;
//				}
//			}
//		}
//}
//int main()
//{
//	srand(time(0));
//	string str;
//	while (cin >> str)
//	{
//		try
//		{
//			SendMsg(str);
//		}
//		catch (const Exception& e)
//		{
//			cout << e.what() << endl << endl;
//		}
//		catch (...)
//		{
//			cout << "Unkown Exception" << endl;
//		}
//	}
//	return 0;
//}


//double Divide(int a, int b)
//{
//	// 当b == 0时抛出异常
//	if (b == 0)
//	{
//		throw "Division by zero condition!";
//	}
//	return (double)a / (double)b;
//}
//void Func()
//{
//	// 这⾥可以看到如果发⽣除0错误抛出异常，另外下⾯的array没有得到释放。
//	// 所以这⾥捕获异常后并不处理异常，异常还是交给外层处理，这⾥捕获了再
//	// 重新抛出去。
//	int* array = new int[10];
//	try
//	{
//		int len, time;
//		cin >> len >> time;
//		cout << Divide(len, time) << endl;
//	}
//	catch (...)
//	{
//		// 捕获异常释放内存
//		cout << "delete []" << array << endl;
//		delete[] array;
//			throw; // 异常重新抛出，捕获到什么抛出什么
//	}
//	cout << "delete []" << array << endl;
//	delete[] array;
//}
//int main()
//{
//	try
//	{
//		Func();
//	}
//	catch (const char* errmsg)
//	{
//		cout << errmsg << endl;
//	}
//	catch (const exception& e)
//	{
//		cout << e.what() << endl;
//	}
//	catch (...)
//	{
//		cout << "Unkown Exception" << endl;
//	}
//	return 0;
//}


//// C++98
//// 这⾥表⽰这个函数只会抛出bad_alloc的异常
//void* operator new (std::size_t size) throw (std::bad_alloc);
//// 这⾥表⽰这个函数不会抛出异常
//void* operator delete (std::size_t size, void* ptr) throw();
//// C++11
//size_type size() const noexcept;
//iterator begin() noexcept;
//const_iterator begin() const noexcept;
//double Divide(int a, int b) noexcept
//{
//	// 当b == 0时抛出异常
//	if (b == 0)
//	{
//		throw "Division by zero condition!";
//	}
//	return (double)a / (double)b;
//}
//int main()
//{
//	try
//	{
//		int len, time;
//		cin >> len >> time;
//		cout << Divide(len, time) << endl;
//	}
//	catch (const char* errmsg)
//	{
//		cout << errmsg << endl;
//	}
//	catch (...)
//	{
//		cout << "Unkown Exception" << endl;
//	}
//	int i = 0;
//	cout << noexcept(Divide(1, 2)) << endl;
//	cout << noexcept(Divide(1, 0)) << endl;
//	cout << noexcept(++i) << endl;
//	return 0;
//}


//智能指针
//template<class T>
//class SmartPtr
//{
//public:
//	// RAII
//	SmartPtr(T* ptr)
//		:_ptr(ptr)
//	{}
//	~SmartPtr()
//	{
//		cout << "delete[] " << _ptr << endl;
//		delete[] _ptr;
//	}
//	// 重载运算符，模拟指针的⾏为，⽅便访问资源
//	T& operator*()
//	{
//		return *_ptr;
//	}
//	T* operator->()
//	{
//		return _ptr;
//	}
//	T& operator[](size_t i)
//	{
//		return _ptr[i];
//	}
//private:
//	T* _ptr;
//};
//double Divide(int a, int b)
//{
//	// 当b == 0时抛出异常
//	if (b == 0)
//	{
//		throw "Divide by zero condition!";
//	}
//	else
//	{
//			return (double)a / (double)b;
//	}
//}
//void Func()
//{
//	// 这⾥使⽤RAII的智能指针类管理new出来的数组以后，程序简单多了
//	SmartPtr<int> sp1 = new int[10];
//	SmartPtr<int> sp2 = new int[10];
//	for (size_t i = 0; i < 10; i++)
//	{
//		sp1[i] = sp2[i] = i;
//	}
//	int len, time;
//	cin >> len >> time;
//	cout << Divide(len, time) << endl;
//}
//int main()
//{
//	try
//	{
//		Func();
//	}
//	catch (const char* errmsg)
//	{
//		cout << errmsg << endl;
//	}
//	catch (const exception& e)
//	{
//		cout << e.what() << endl;
//	}
//	catch (...)
//	{
//		cout << "未知异常" << endl;
//	}
//	return 0;
//}


struct Date
{
	int _year;
	int _month;
	int _day;

	Date(int year = 1, int month = 1, int day = 1)
		:_year(year), 
		_month(month)
		, _day(day)
	{}

	~Date()
	{
		cout << "~Date()" << endl;
	}
};
//
//int main()
//{
//	auto_ptr<Date> ap1(new Date);
//	// 拷⻉时，管理权限转移，被拷⻉对象ap1悬空
//	auto_ptr<Date> ap2(ap1);
//
//	// 空指针访问，ap1对象已经悬空
//	//ap1->_year++;
//
//	unique_ptr<Date> up1(new Date);
//	// 不⽀持拷⻉
//	//unique_ptr<Date> up2(up1);
//	// ⽀持移动，但是移动后up1也悬空，所以使⽤移动要谨慎
//	unique_ptr<Date> up3(move(up1));
//
//	shared_ptr<Date> sp1(new Date);
//	// ⽀持拷⻉
//	shared_ptr<Date> sp2(sp1);
//	shared_ptr<Date> sp3(sp2);
//	cout << sp1.use_count() << endl;
//	sp1->_year++;
//	cout << sp1->_year << endl;
//	cout << sp2->_year << endl;
//	cout << sp3->_year << endl;
//
//	// ⽀持移动，但是移动后sp1也悬空，所以使⽤移动要谨慎
//	shared_ptr<Date> sp4(move(sp1));
//
//	return 0;
//}


//
namespace wzz
{
	template<class T>
	class auto_ptr
	{
	public:
		auto_ptr(T* ptr)
			:_ptr(ptr)
		{}
		auto_ptr(auto_ptr<T>& sp)
			:_ptr(sp._ptr)
		{
			// 管理权转移
			sp._ptr = nullptr;
		}
		auto_ptr<T>& operator=(auto_ptr<T>& ap)
		{
			// 检测是否为⾃⼰给⾃⼰赋值
			if (this != &ap)
			{
				// 释放当前对象中资源
				if (_ptr)
					delete _ptr;
				// 转移ap中资源到当前对象中
				_ptr = ap._ptr;
				ap._ptr = NULL;
			}
			return *this;
		}
		~auto_ptr()
		{
			if (_ptr)
			{
				cout << "delete:" << _ptr << endl;
				delete _ptr;
			}
		}
		// 像指针⼀样使⽤
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};

	template<class T>
	class unique_ptr
	{
	public:
		explicit unique_ptr(T* ptr)
			:_ptr(ptr)
		{}
		~unique_ptr()
		{
			if (_ptr)
			{
				cout << "delete:" << _ptr << endl;
				delete _ptr;
			}
		}
		// 像指针⼀样使⽤
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
		unique_ptr(const unique_ptr<T>& sp) = delete;
		unique_ptr<T>& operator=(const unique_ptr<T>& sp) = delete;
		unique_ptr(unique_ptr<T>&& sp)
			:_ptr(sp._ptr)
		{
			sp._ptr = nullptr;
		}
		unique_ptr<T>& operator=(unique_ptr<T>&& sp)
		{
			delete _ptr;
			_ptr = sp._ptr;
			sp._ptr = nullptr;
		}
	private:
		T* _ptr;
	};

	template<class T>
	class shared_ptr
	{
	public:
		explicit shared_ptr(T* ptr = nullptr)
			: _ptr(ptr)
			, _pcount(new atomic<int>(1))
		{}

		template<class D>
		shared_ptr(T* ptr, D del)
			: _ptr(ptr)
			, _pcount(new atomic<int>(1))
			, _del(del)
		{}

		shared_ptr(const shared_ptr<T>& sp)
			:_ptr(sp._ptr)
			, _pcount(sp._pcount)
			, _del(sp._del)
		{
			++(*_pcount);
		}

		void release()
		{
			if (--(*_pcount) == 0)
			{
				// 最后⼀个管理的对象，释放资源
				_del(_ptr);
				delete _pcount;
				_ptr = nullptr;
				_pcount = nullptr;
			}
		}

		shared_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			if (_ptr != sp._ptr)
			{
				release();
				_ptr = sp._ptr;
				_pcount = sp._pcount;
				++(*_pcount);
				_del = sp._del;
			}
			return *this;
		}

		~shared_ptr()
		{
			release();
		}

		T* get() const
		{
		return _ptr;
		}

		int use_count() const
		{
			return *_pcount;
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

	private:
		T* _ptr;
		//int* _pcount;
		atomic<int>* _pcount;
		function<void(T*)> _del = [](T* ptr) {delete ptr; };
	};

	// 需要注意的是我们这⾥实现的shared_ptr和weak_ptr都是以最简洁的⽅式实现的，
// 只能满⾜基本的功能，这⾥的weak_ptr lock等功能是⽆法实现的，想要实现就要
// 把shared_ptr和weak_ptr⼀起改了，把引⽤计数拿出来放到⼀个单独类型，shared_ptr
// 和weak_ptr都要存储指向这个类的对象才能实现，有兴趣可以去翻翻源代码
	template<class T>
	class weak_ptr
	{
	public:
		weak_ptr()
		{}

		weak_ptr(const shared_ptr<T>& sp)
			:_ptr(sp.get())
		{}

		weak_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			_ptr = sp.get();
			return *this;
		}
	private:
		T* _ptr = nullptr;
	};
}
//int main()
//{
//	wzz::auto_ptr<Date> ap1(new Date);
//	// 拷⻉时，管理权限转移，被拷⻉对象ap1悬空
//	wzz::auto_ptr<Date> ap2(ap1);
//
//	// 空指针访问，ap1对象已经悬空
//	//ap1->_year++;
//
//	wzz::unique_ptr<Date> up1(new Date);
//	// 不⽀持拷⻉
//	//unique_ptr<Date> up2(up1);
//	// ⽀持移动，但是移动后up1也悬空，所以使⽤移动要谨慎
//	wzz::unique_ptr<Date> up3(move(up1));
//
//	wzz::shared_ptr<Date> sp1(new Date);
//	// ⽀持拷⻉
//	wzz::shared_ptr<Date> sp2(sp1);
//	wzz::shared_ptr<Date> sp3(sp2);
//	cout << sp1.use_count() << endl;
//	sp1->_year++;
//	cout << sp1->_year << endl;
//	cout << sp2->_year << endl;
//	cout << sp3->_year << endl;
//
//	return 0;
//}

template<class T>
void DeleteArrayFunc(T* ptr)
{
	delete[] ptr;
}
template<class T>
class DeleteArray
{
public:
	void operator()(T* ptr)
	{
		delete[] ptr;
	}
};
class Fclose
{
public:
	void operator()(FILE* ptr)
	{
		cout << "fclose:" << ptr << endl;
		fclose(ptr);
	}
};
//int main()
//{
//	// 这样实现程序会崩溃
//	// unique_ptr<Date> up1(new Date[10]);
//	// shared_ptr<Date> sp1(new Date[10]);
//	// 
//	// 解决⽅案1
//	// 因为new[]经常使⽤，所以unique_ptr和shared_ptr
//	// 实现了⼀个特化版本，这个特化版本析构时⽤的delete[]
//	unique_ptr<Date[]> up1(new Date[5]);
//	shared_ptr<Date[]> sp1(new Date[5]);
//
//	// 解决⽅案2
//	// 
//	// 仿函数对象做删除器
//	//unique_ptr<Date, DeleteArray<Date>> up2(new Date[5], DeleteArray<Date>());
//	// unique_ptr和shared_ptr⽀持删除器的⽅式有所不同
//	// unique_ptr是在类模板参数⽀持的，shared_ptr是构造函数参数⽀持的
//	// 这⾥没有使⽤相同的⽅式还是挺坑的
//	// 使⽤仿函数unique_ptr可以不在构造函数传递，因为仿函数类型构造的对象直接就可以调⽤
//	// 但是下⾯的函数指针和lambda的类型不可以
//	unique_ptr<Date, DeleteArray<Date>> up2(new Date[5]);
//	shared_ptr<Date> sp2(new Date[5], DeleteArray<Date>());
//
//	// 函数指针做删除器
//	unique_ptr<Date, void(*)(Date*)> up3(new Date[5], DeleteArrayFunc<Date>);
//	shared_ptr<Date> sp3(new Date[5], DeleteArrayFunc<Date>);
//
//	// lambda表达式做删除器
//	auto delArrOBJ = [](Date* ptr) {delete[] ptr; };
//	unique_ptr<Date, decltype(delArrOBJ)> up4(new Date[5], delArrOBJ);
//	shared_ptr<Date> sp4(new Date[5], delArrOBJ);
//
//	// 实现其他资源管理的删除器
//	shared_ptr<FILE> sp5(fopen("Test.cpp", "r"), Fclose());
//	shared_ptr<FILE> sp6(fopen("Test.cpp", "r"), [](FILE* ptr) {
//		cout << "fclose:" << ptr << endl;
//		fclose(ptr);
//		});
//	return 0;
//}

//int main()
//{
//	shared_ptr<Date> sp1(new Date(2024, 9, 11));
//	shared_ptr<Date> sp2 = make_shared<Date>(2024, 9, 11);
//	auto sp3 = make_shared<Date>(2024, 9, 11);
//	shared_ptr<Date> sp4;
//
//	// if (sp1.operator bool())
//	if (sp1)
//		cout << "sp1 is not nullptr" << endl;
//	if (!sp4)
//		cout << "sp1 is nullptr" << endl;
//
//	// 报错
//	//shared_ptr<Date> sp5 = new Date(2024, 9, 11);
//	//unique_ptr<Date> sp6 = new Date(2024, 9, 11);
// 
//	return 0;
//}


struct ListNode
{
	int _data;

	/*std::shared_ptr<ListNode> _next;
	std::shared_ptr<ListNode> _prev;*/

	// 这⾥改成weak_ptr，当n1->_next = n2;绑定shared_ptr时不增加n2的引⽤计数，不参与资源释放的管理，就不会形成循环引⽤了
	std::weak_ptr<ListNode> _next;
	std::weak_ptr<ListNode> _prev;

	~ListNode()
	{
		cout << "~ListNode()" << endl;
	}
};
//int main()
//{
//	// 循环引⽤ -- 内存泄露
//	std::shared_ptr<ListNode> n1(new ListNode);
//	std::shared_ptr<ListNode> n2(new ListNode);
//
//	cout << n1.use_count() << endl;
//	cout << n2.use_count() << endl;
//
//	n1->_next = n2;
//	n2->_prev = n1;
//
//	cout << n1.use_count() << endl;
//	cout << n2.use_count() << endl;
//
//	// weak_ptr不⽀持管理资源，不⽀持RAII
//	// weak_ptr是专⻔绑定shared_ptr，不增加他的引⽤计数，作为⼀些场景的辅助管理
//	//std::weak_ptr<ListNode> wp(new ListNode);
//
//	return 0;
//}

//int main()
//{
//	std::shared_ptr<string> sp1(new string("111111"));
//	std::shared_ptr<string> sp2(sp1);
//	std::weak_ptr<string> wp = sp1;
//	cout << wp.expired() << endl;
//	cout << wp.use_count() << endl;
//
//	// sp1和sp2都指向了其他资源，则weak_ptr就过期了
//	sp1 = make_shared<string>("222222");
//	cout << wp.expired() << endl;
//	cout << wp.use_count() << endl;
//
//	sp2 = make_shared<string>("333333");
//	cout << wp.expired() << endl;
//	cout << wp.use_count() << endl;
//
//	wp = sp1;
//	//std::shared_ptr<string> sp3 = wp.lock();
//	auto sp3 = wp.lock();
//	cout << wp.expired() << endl;
//	cout << wp.use_count() << endl;
//
//	*sp3 += "###";
//	cout << *sp1 << endl;
//
//	return 0;
//}

struct AA
{
	int _a1 = 0;
	int _a2 = 0;

	~AA()
	{
		cout << "~AA()" << endl;
	}
};
int main()
{
	wzz::shared_ptr<AA> p(new AA);
	const size_t n = 100000;

	mutex mtx;
	auto func = [&]()
		{
			for (size_t i = 0; i < n; ++i)
			{
				// 这⾥智能指针拷⻉会++计数
				wzz::shared_ptr<AA> copy(p);
				{
					unique_lock<mutex> lk(mtx);
					copy->_a1++;
					copy->_a2++;
				}
			}
		};

	thread t1(func);
	thread t2(func);

	t1.join();
	t2.join();

	cout << p->_a1 << endl;
	cout << p->_a2 << endl;

	cout << p.use_count() << endl;

	return 0;
}
